﻿#region using statements

using System;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

using NGen;
using NGen.Managers.GameObject;
using NGen.Managers.Input;

using Nuclex.Input;

using XNAGameDemo.GameStates;

#endregion

namespace XNAGameDemo.GameObjects
{
	/// <summary>
	/// 	A ball which bounces off of the screen edge
	/// </summary>
	public class BouncingBall : GameObject2D, IMouseListener
	{
		private static readonly Random sc_random = new Random(DateTime.Now.Millisecond);

		private static int m_windowWidth;

		private static int m_windowHeight;

		private float m_angularRotation;

		private float m_angularVelocity;

		private Rectangle m_boundingBox;

		private Vector2 m_velocity;

		#region IMouseListener Members

		public void MousePressed(MouseButtons p_button) {
			if(p_button == MouseButtons.Left) {
				//if this ball is left clicked, destroy it and add points
				if(m_boundingBox.Contains(GameEngine.GetService<IManagerInput>().GetMouseState().X, GameEngine.GetService<IManagerInput>().GetMouseState().Y)) {
					Destroy(Id);
					GameEngine.GetService<GameStatePlay1.Play1Score>().m_points++;
				}
			}
		}

		public void MouseReleased(MouseButtons p_button) {}

		public void MouseMoved(float p_x, float p_y) {}

		public void MouseWheelScroll(float p_ticks) {}

		#endregion

		protected override void _Initialize() {
			m_windowWidth = GameEngine.GameWindow.ClientBounds.Width;
			m_windowHeight = GameEngine.GameWindow.ClientBounds.Height;
			base._Initialize();

			//let this ball receive mouse events
			GameEngine.GetService<IManagerInput>().AddMouseListener(this);
			m_texture = GameEngine.GameContent.Load<Texture2D>("Content\\Textures\\baseball");

			//make the texture smaller
			m_scale.X = 0.25f;
			m_scale.Y = 0.25f;

			//randomize ball position
			m_position = new Vector2(sc_random.Next(GameEngine.GameWindow.ClientBounds.Width) * 0.8f, sc_random.Next(GameEngine.GameWindow.ClientBounds.Height) * 0.8f);

			//prevent balls from getting stuck on top and left screen edges
			m_position += new Vector2(GameEngine.GameWindow.ClientBounds.Width * 0.1f, GameEngine.GameWindow.ClientBounds.Height * 0.1f);

			//set the center point so the texture rotates around the middle of the 
			//texture and not the top left corner
			m_origin.X = m_texture.Width / 2.0f;
			m_origin.Y = m_texture.Height / 2.0f;

			//create a bounding volume
			m_boundingBox = new Rectangle((int) m_position.X, (int) m_position.Y, (int) (m_texture.Width * m_scale.X), (int) (m_texture.Height * m_scale.Y));

			//randomize velocity, max speed of 50 pixels per second
			m_velocity = new Vector2(((float) sc_random.NextDouble()) * 2.0f - 1.0f, ((float) sc_random.NextDouble() * 2.0f) - 1.0f);
			m_velocity.Normalize();
			Vector2.Multiply(ref m_velocity, (float) sc_random.NextDouble() * 200, out m_velocity);

			//random color assigned
			m_textureTint = new Color((float) sc_random.NextDouble(), (float) sc_random.NextDouble(), (float) sc_random.NextDouble());

			//randomize rotation rate
			m_angularRotation = ((float) sc_random.NextDouble() * 2.0f - 1.0f) / 10.0f;
			m_angularVelocity = ((float) sc_random.NextDouble() * 2.0f - 1.0f) * 5.0f;
		}

		protected override void _Cleanup() {
			base._Cleanup();
			//disable mouse notifications
			GameEngine.GetService<IManagerInput>().RemoveMouseListener(this);
		}

		protected override void _Update(GameTime p_gameTime) {
			//move the ball
			m_position += m_velocity * (float) p_gameTime.ElapsedGameTime.TotalSeconds;

			//make sure balls stays within window
			if(m_position.X + m_texture.Bounds.Width * m_scale.X - m_origin.X * m_scale.X > m_windowWidth ||
			   m_position.X + m_velocity.X - m_origin.X * m_scale.X < 0) {
				m_velocity.X *= -1f;
			}
			if(m_position.Y + m_texture.Bounds.Height * m_scale.Y - m_origin.Y * m_scale.Y > m_windowHeight ||
			   m_position.Y + m_velocity.Y - m_origin.Y * m_scale.Y < 0) {
				m_velocity.Y *= -1f;
			}

			//objects lower on the screen will appear in front of objects higher on screen
			m_zDepth = 1 - (m_position.Y / m_windowHeight + .001f);

			//update bounding box to be at the new position
			m_boundingBox.X = (int) (m_position.X - m_origin.X * m_scale.X);
			m_boundingBox.Y = (int) (m_position.Y - m_origin.Y * m_scale.Y);

			//roate ball by its angular velocity
			m_angularRotation += m_angularVelocity * (float) p_gameTime.ElapsedGameTime.TotalSeconds;
		}

		protected override void _Draw(GameTime p_gameTime) {
			if(m_texture == null) {
				return;
			}

			//draw the texture, must be overridden because the base GameObject2D 
			//class does not use the rotation parameter
			GameEngine.SpriteBatch.Draw(m_texture, m_position, null, m_textureTint, m_angularRotation, m_origin, m_scale, SpriteEffects.None, m_zDepth);
		}
	}
}